package hw3.proxy.core;

import hw3.exception.StdErrReporterException;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import org.apache.http.HttpException;
import org.apache.http.HttpResponse;
import org.apache.http.impl.DefaultHttpServerConnection;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;

/**
 * This class is responsible for handling the communication with clients.
 * 
 * @author Adam Levi
 * @author Marina Skarbovsky
 *
 */
public class ClientConnHandler
{
	/**
	 * Constructor 
	 * @param port - the port that is used to listen for clients' connections.
	 */
	public ClientConnHandler (int port)
	{
		m_Port = port;
		m_httpConnectionParams = new BasicHttpParams();
		ConfigurationProperties.initializeHTTPConnectionParams(m_httpConnectionParams);
	}
	
	/**
	 * Create the server socket.
	 * @throws IOException
	 */
	public void initialize() throws IOException
	{
		m_ServerSocket = new ServerSocket(m_Port);
	}
	
	/**
	 * Close the server socket.
	 */
	public void finalize() throws IOException
	{
		m_ServerSocket.close();
	}
	
	/**
	 * Accept one client connection, and receive an HTTP request from the client
	 * @return HttpRequestToHandle which contains the HTTP request and DefaultHttpServerConnection to the client
	 * @throws IOException
	 * @throws HttpException
	 */
	public HttpRequestToHandle getHttpRequestToHandle() throws IOException, HttpException
	{
		Socket currClientSocket = m_ServerSocket.accept();
		DefaultHttpServerConnection httpConnection = new DefaultHttpServerConnection();
		httpConnection.bind(currClientSocket, m_httpConnectionParams);
		HttpRequestToHandle request;
		try 
		{
			request = new HttpRequestToHandle(
									httpConnection,
									httpConnection.receiveRequestHeader());
		} 
		catch (HttpException e) 
		{
			currClientSocket.close();
			throw(e);
		}
		return request;	
	}
	
	/**
	 * Send an HTTP response to a client
	 * @param response - the HTTP response to send
	 * @param conn - DefaultHttpServerConnection with the client
	 * @throws HttpException
	 * @throws IOException
	 */
	public void sendResponse(HttpResponse response, DefaultHttpServerConnection conn) throws HttpException, IOException
	{
		if (!conn.isOpen() || conn.isStale())
		{
			return;
		}
		conn.sendResponseHeader(response);
		if (response.getEntity() != null)
		{
			try
			{
				conn.sendResponseEntity(response);
			}
			catch(Exception e)
			{
				StdErrReporterException.reportErrorFromException(
						ClientConnHandler.class.getName(),
						"the following error occured while attempting to send response body to client:", 
						e);
			}
		}
		conn.flush();
	}
	
	private int m_Port;
	private ServerSocket m_ServerSocket;
	private HttpParams m_httpConnectionParams; 
}
